#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ai_rw.h"
#include "ai_test.h"
#include "thread_ctrl.h"
#include "ietAiLib.h"

#define AI_DEF_DMA_SIZE     (64 * 1024 - 32)    /* AI DMA 大小 128KByte */
#define AI_PRINT_BYTES      32                  /* AI DMA 预留数据长度 */
#define AI_RANGE_10V_LSB    305                 /* 305uV */
#define AI_RANGE_2V5_LSB    76                  /* 76uV */
#define AI_RANGE_5V_LSB     152                 /* 152uV */

#define AI_UV_2_V           1000000             /* AI uV -> V */
#define AI_UV_2_MV          1000                /* AI uV -> V */
#define AI_SAMP_RESISTOR    200                 /* AI 采样电阻, Ω */

/* 定义中断回调函数类型 */
void aiIrqCallback(double *data)
{
    struct ai_param_t *pparam = &ai_param;
    uint8_t i = 0;
    double value[AI_MAX_NUM];

    memcpy(value, data, pparam->max_num * sizeof(double));
    for (i = 0; i < pparam->max_num; i++) {
        if (pparam->val_type == 0) {
            printf("aiIrqCallback AI %2d value %.6lfV\n", i, value[i]);
        } else {
            printf("aiIrqCallback AI %2d value %.6lfmA\n", i, (1000.0 * value[i] / AI_SAMP_RESISTOR));
        }
    }
}

/* 定义 DMA 回调函数类型 */
void aiDmaCallback(uint8_t *data)
{
    struct ai_param_t *pparam = &ai_param;
    struct ai_dev_t *pdev= &pparam->dev[0];
    uint8_t buffer[AI_DEF_DMA_SIZE];
    ssize_t readCnt = AI_DEF_DMA_SIZE;
    int offset = 0;
    int i = 0;
    int j = 0;
    double value = 0.0;

    memcpy(buffer, data, sizeof(buffer));
    for (offset = 0; offset < readCnt; offset += 2 * ai_param.max_num) {
        if ((offset + 2 * ai_param.max_num) > readCnt) {
            fprintf(stderr, "Left %zd channel data, should be %d\n", 
                    ((offset + 2 * ai_param.max_num) - readCnt) / 2, ai_param.max_num);
            break;
        }
        printf("--- Block %d ---\n", (offset / (2 * ai_param.max_num) + 1));
        for (i = 0; i < ai_param.max_num; i++) {
            j = offset + i * 2;
            /* 组合两个字节为16位数据(小端模式) */
            int16_t raw_value = ((int16_t)buffer[j + 1] << 8) | buffer[j];
            
            /* 应用转换公式*/
            if (pdev->range == AI_RANGE_2V5) {
                value = 1.0 * raw_value * AI_RANGE_2V5_LSB / AI_UV_2_V;
            } else if (pdev->range == AI_RANGE_5V) {
                value = 1.0 * raw_value * AI_RANGE_5V_LSB / AI_UV_2_V;
            } else {
                value = 1.0 * raw_value * AI_RANGE_10V_LSB / AI_UV_2_V;
            }
            if (pparam->val_type == 0) {
                printf("Channel %02d: raw=0x%04x (%5u) -> %.6lfV\n", 
                       i, raw_value, raw_value, value);
            } else {
                printf("Channel %02d: raw=0x%04x (%5u) -> %.6lfmA\n", 
                       i, raw_value, raw_value, (1000.0 * value / AI_SAMP_RESISTOR));
            }
        }
    }
}

/* 接收 AI 数据线程函数 */
void *recv_ai_thread(void *arg)
{
    struct ai_dev_t *pdev = (struct ai_dev_t *)arg;
    struct ai_param_t *pparam = (struct ai_param_t *)pdev->parent;
    struct thread_param_t *pthread = pdev->read_thread;
    int ret = 0;
    int i = 0;
    // int fd = pdev->fd;
    uint32_t u32_val = 0;
    double value = 0;

    struct AimParam devParam = {
        .mode = pparam->mode,
        .sampleRate = pparam->sample,
        .interruptRate = pparam->samp_tim,
        .filtWindow = pparam->slid_win,
    };
    for (i = 0; i < pparam->dev_num; i++) {
        devParam.range[i] = pparam->dev[i].range;
    }

    /* 检查参数是否有效 */
    if (!pthread || !pthread->name) {
        fprintf(stderr, "Invalid parameters for %s\n", __func__);
        return NULL;
    }

    /* 线程取消 SIGUSR1 的阻塞 */
    init_thread_user_signal();
    /* 配置 AI 参数 */
    switch (pparam->mode) {
    case AI_MOD_SMP_TIM:
        registerIrqCallback(aiIrqCallback);
        break;
    case AI_MOD_RAW_DMA:
        registerDmaCallback(aiDmaCallback);
        break;
    default:
        break;
    }
    AIMInit(devParam);
    usleep(100000);
    // printf("Start %s receive thread...\n", pthread->name);
    while (!pthread->exit_sig) {
        for (i = 0; (pparam->read_cnt == -1 || i < pparam->read_cnt) && !pthread->exit_sig; i++) {
            switch (pparam->mode) {
            case AI_MOD_SMP:
                /* 获取 AI 数值 */
                ret = AIMRead(pdev->index, &u32_val);
                if (ret < 0) {
                    printf("AIMRead AI %2d value failed\n", pdev->index);
                    return NULL;
                }
                printf("AIMRead     AI %2d value %duV\n", pdev->index, u32_val);
                if (pparam->val_type == 0) {
                    ret = AIMReadReal(pdev->index, 0, &value);
                    if (ret < 0) {
                        printf("AIMReadReal AI %2d value failed\n", pdev->index);
                        return NULL;
                    }
                    printf("AIMReadReal AI %2d value %.6lfV\n", pdev->index, value);
                } else {
                    ret = AIMReadReal(pdev->index, 1, &value);
                    if (ret < 0) {
                        printf("AIMReadReal AI %2d value failed\n", pdev->index);
                        return NULL;
                    }
                    printf("AIMReadReal AI %2d value %.6lfmA\n", pdev->index, value);
                }
                break;
            case AI_MOD_SMP_TIM:
                /* 获取 AI 数值 */
                break;
            case AI_MOD_RAW_DMA:
                break;
            case AI_MOD_RAW:
                /* 获取 AI 数值 */
                ret = AIMRead(pdev->index, &u32_val);
                if (ret < 0) {
                    printf("AIMRead AI %2d value failed\n", pdev->index);
                    return NULL;
                }
                printf("AIMRead     AI %2d value %duV\n", pdev->index, u32_val);
                if (pparam->val_type == 0) {
                    ret = AIMReadReal(pdev->index, 0, &value);
                    if (ret < 0) {
                        printf("AIMReadReal AI %2d value failed\n", pdev->index);
                        return NULL;
                    }
                    printf("AIMReadReal AI %2d value %.6lfV\n", pdev->index, value);
                } else {
                    ret = AIMReadReal(pdev->index, 1, &value);
                    if (ret < 0) {
                        printf("AIMReadReal AI %2d value failed\n", pdev->index);
                        return NULL;
                    }
                    printf("AIMReadReal AI %2d value %.6lfmA\n", pdev->index, value);
                }
                break;
            default:
                fprintf(stderr, "Read %s failed, mode=%d not support\n", pdev->path, pparam->mode);
                break;
            }
        }
        // printf("Read %s %d data done\n", pthread->name, pparam->read_cnt);
        break;
    }
    // printf("%s %s return\n", pthread->name, __func__);

    return NULL;
}
